package cn.jingyuan.owl.dao.mybatis;

import cn.jingyuan.owl.dao.core.CrudDao;

import java.io.Serializable;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public abstract class AbstractMyBatisCrudDao<E, ID extends Serializable>
    extends AbstractMyBatisEmptyDao<E, ID>
    implements CrudDao<E, ID> {
    // mapper 也按照如下定义的顺序进行编写

    // @formatter:off
    protected static final String SQL_INSERT = "insert";
    protected static final String SQL_INSERT_SELECTIVE = "insertSelective";

    protected static final String SQL_INSERTS = "inserts";
    protected static final String SQL_INSERTS_SELECTIVE = "insertsSelective";

    protected static final String SQL_DELETE_BY_ID = "deleteById";
    protected static final String SQL_DELETE_BY_IDS = "deleteByIds";
    protected static final String SQL_DELETES_ALL = "deletesAll";

    protected static final String SQL_UPDATE_BY_ID = "updateById";
    protected static final String SQL_UPDATE_BY_IDS = "updateByIds";

    protected static final String SQL_UPDATE_SELECTIVE_BY_ID = "updateSelectiveById";
    protected static final String SQL_UPDATE_SELECTIVE_BY_IDS = "updateSelectiveByIds";

    protected static final String SQL_GET_BY_ID = "getById";
    protected static final String SQL_GET_BY_IDS = "getByIds";
    protected static final String SQL_GET_ALL = "getAll";

    protected static final String SQL_COUNT = "count";
    protected static final String SQL_COUNT_BY_IDS = "countByIds";
    // @formatter:on

    /** xml mapper 命名空间 */
    private String namespace;

    private Map<String, String> statementCache = new ConcurrentHashMap<>();

    public String getNamespace() {
        return namespace;
    }

    public void setNamespace(String namespace) {
        this.namespace = namespace;
    }

    @Override
    public int insert(E entity) {
        return getSqlSessionTemplate()
            .insert(getStatement(SQL_INSERT), entity);
    }

    @Override
    public int insertSelective(E entity) {
        return getSqlSessionTemplate()
            .insert(getStatement(SQL_INSERT_SELECTIVE), entity);
    }

    @Override
    public int inserts(List<E> entities) {
        return getSqlSessionTemplate()
            .insert(getStatement(SQL_INSERTS), entities);
    }

    @Override
    public int insertsSelective(List<E> entities) {
        return getSqlSessionTemplate()
            .insert(getStatement(SQL_INSERTS_SELECTIVE), entities);
    }

    @Override
    public int deleteById(ID id) {
        return getSqlSessionTemplate()
            .delete(getStatement(SQL_DELETE_BY_ID), id);
    }

    @Override
    public int deleteByIds(List<ID> ids) {
        return getSqlSessionTemplate()
            .delete(getStatement(SQL_DELETE_BY_IDS), ids);
    }

    @Override
    public int deletesAll() {
        return getSqlSessionTemplate()
            .delete(getStatement(SQL_DELETES_ALL));
    }

    @Override
    public int updateById(E entity) {
        return getSqlSessionTemplate()
            .update(getStatement(SQL_UPDATE_BY_ID), entity);
    }

    @Override
    public int updateByIds(List<E> entities) {
        return getSqlSessionTemplate()
            .update(getStatement(SQL_UPDATE_BY_IDS), entities);
    }

    @Override
    public int updateSelectiveById(E entity) {
        return getSqlSessionTemplate()
            .update(getStatement(SQL_UPDATE_SELECTIVE_BY_ID), entity);
    }

    @Override
    public int updateSelectiveByIds(List<E> entities) {
        return getSqlSessionTemplate()
            .update(getStatement(SQL_UPDATE_SELECTIVE_BY_IDS), entities);
    }

    @Override
    public E getById(ID id) {
        return getSqlSessionTemplate()
            .selectOne(getStatement(SQL_GET_BY_ID), id);
    }

    @Override
    public List<E> getByIds(List<ID> ids) {
        return getSqlSessionTemplate()
            .selectList(getStatement(SQL_GET_BY_IDS), ids);
    }

    @Override
    public List<E> getAll() {
        return getSqlSessionTemplate()
            .selectList(getStatement(SQL_GET_ALL));
    }

    @Override
    public int count() {
        return getSqlSessionTemplate()
            .selectOne(getStatement(SQL_COUNT));
    }

    @Override
    public int countByIds(List<ID> ids) {
        return getSqlSessionTemplate()
            .selectOne(getStatement(SQL_COUNT_BY_IDS), ids);
    }


    protected String getStatement(String statement) {
        String cachedStatement = statementCache.get(statement);
        if (null != cachedStatement) {
            return cachedStatement;
        }

        String finalStatement;
        if (null != namespace) {
            finalStatement = new StringBuilder(namespace)
                .append(".")
                .append(statement)
                .toString();
        } else {
            Class<?>[] interfaces = this.getClass().getInterfaces();

            String name;
            if (0 != interfaces.length) {
                Class<?> firstInterface = interfaces[0];
                name = firstInterface.getName();
            } else {
                name = this.getClass().getName();
            }

            finalStatement = new StringBuffer(name)
                .append(".")
                .append(statement)
                .toString();
        }

        statementCache.put(statement, finalStatement);

        return finalStatement;
    }

}
